#include "propagation-models.h"
#include "ns3/log.h"
#include "ns3/mobility-model.h"  // 添加MobilityModel头文件
#include "ns3/vector.h"          // 添加Vector头文件
#include <cmath>

namespace ns3 {

NS_LOG_COMPONENT_DEFINE("PropagationModels");

//---------------------- GroundStationPropagationLossModel ---------------------//

NS_OBJECT_ENSURE_REGISTERED(GroundStationPropagationLossModel);

TypeId 
GroundStationPropagationLossModel::GetTypeId()
{
    static TypeId tid = TypeId("ns3::GroundStationPropagationLossModel")
        .SetParent<PropagationLossModel>()
        .SetGroupName("SAGINIoV")
        .AddConstructor<GroundStationPropagationLossModel>();
    return tid;
}

GroundStationPropagationLossModel::GroundStationPropagationLossModel()
    : m_coverageRadius(1000.0)
{
    NS_LOG_FUNCTION(this);
}

void 
GroundStationPropagationLossModel::SetCoverageRadius(double radius)
{
    NS_LOG_FUNCTION(this << radius);
    m_coverageRadius = radius;
}

double 
GroundStationPropagationLossModel::GetCoverageRadius() const
{
    return m_coverageRadius;
}

double 
GroundStationPropagationLossModel::DoCalcRxPower(double txPowerDbm,
                                               Ptr<MobilityModel> a,
                                               Ptr<MobilityModel> b) const
{
    NS_LOG_FUNCTION(this << txPowerDbm << a << b);
    
    double distance = a->GetDistanceFrom(b);
    
    // 如果距离超过覆盖半径，信号过弱
    if (distance > m_coverageRadius) {
        return -1000.0; // 极低的接收功率表示不可接收
    }
    
    // 简化的路径损耗模型
    // 自由空间路径损耗: 20log10(d) + 20log10(f) - 147.55
    // 假设频率为2.4GHz, 简化为: 20log10(d) + 40.0
    double pathLoss = 20.0 * std::log10(distance) + 40.0;
    
    // 接收功率 = 发送功率 - 路径损耗
    double rxPowerDbm = txPowerDbm - pathLoss;
    
    return rxPowerDbm;
}

int64_t 
GroundStationPropagationLossModel::DoAssignStreams(int64_t stream)
{
    return 0;
}

//---------------------- SatellitePropagationLossModel ---------------------//

NS_OBJECT_ENSURE_REGISTERED(SatellitePropagationLossModel);

TypeId 
SatellitePropagationLossModel::GetTypeId()
{
    static TypeId tid = TypeId("ns3::SatellitePropagationLossModel")
        .SetParent<PropagationLossModel>()
        .SetGroupName("SAGINIoV")
        .AddConstructor<SatellitePropagationLossModel>();
    return tid;
}

SatellitePropagationLossModel::SatellitePropagationLossModel()
    : m_maximumElevationAngle(45.0)
{
    NS_LOG_FUNCTION(this);
}

void 
SatellitePropagationLossModel::SetMaximumElevationAngle(double angle)
{
    NS_LOG_FUNCTION(this << angle);
    m_maximumElevationAngle = angle;
}

double 
SatellitePropagationLossModel::GetMaximumElevationAngle() const
{
    return m_maximumElevationAngle;
}

double 
SatellitePropagationLossModel::DoCalcRxPower(double txPowerDbm,
                                           Ptr<MobilityModel> a,
                                           Ptr<MobilityModel> b) const
{
    NS_LOG_FUNCTION(this << txPowerDbm << a << b);
    
    // 获取位置
    Vector satPos = a->GetPosition();
    Vector vehiclePos = b->GetPosition();
    
    // 计算卫星高度
    double satelliteAltitude = satPos.z;
    
    // 计算地面距离
    double groundDistance = std::sqrt(
        std::pow(satPos.x - vehiclePos.x, 2) + 
        std::pow(satPos.y - vehiclePos.y, 2)
    );
    
    // 计算仰角（度）
    double elevationAngle = std::atan2(satelliteAltitude, groundDistance) * 180.0 / M_PI;
    
    // 如果仰角小于阈值，则信号太弱
    if (elevationAngle < m_maximumElevationAngle) {
        return -1000.0; // 极低的接收功率表示不可接收
    }
    
    // 计算实际距离
    double distance = a->GetDistanceFrom(b);
    
    // 简化的卫星路径损耗模型
    // 自由空间路径损耗: 20log10(d) + 20log10(f) - 147.55
    // 卫星链路额外损耗: + 10.0 (考虑大气层衰减)
    double pathLoss = 20.0 * std::log10(distance) + 50.0;
    
    // 接收功率 = 发送功率 - 路径损耗
    double rxPowerDbm = txPowerDbm - pathLoss;
    
    return rxPowerDbm;
}

int64_t 
SatellitePropagationLossModel::DoAssignStreams(int64_t stream)
{
    return 0;
}

//---------------------- PropagationModelFactory ---------------------//

Ptr<PropagationLossModel> 
PropagationModelFactory::CreateGroundStationPropagationModel(double coverageRadius)
{
    Ptr<GroundStationPropagationLossModel> model = CreateObject<GroundStationPropagationLossModel>();
    model->SetCoverageRadius(coverageRadius);
    return model;
}

Ptr<PropagationLossModel> 
PropagationModelFactory::CreateSatellitePropagationModel(double maximumElevationAngle)
{
    Ptr<SatellitePropagationLossModel> model = CreateObject<SatellitePropagationLossModel>();
    model->SetMaximumElevationAngle(maximumElevationAngle);
    return model;
}

} // namespace ns3
